Skip to content

gh-159136: Avoid stop-the-world when setting function name attributes - #159269

Open
nascheme wants to merge 5 commits into
python:mainfrom
nascheme:gh-159136-func-attrs
Open

nascheme wants to merge 5 commits into
python:mainfrom
nascheme:gh-159136-func-attrs

Conversation

@nascheme

@nascheme nascheme commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

Setting __name__, __qualname__, __doc__ or __module__ on a function stopped the world in the free-threaded build since gh-154826 and gh-154851, making functools.wraps() orders of magnitude slower with multiple threads.

Use the per-object critical section and _PyObject_XSetRefDelayed() instead, as gen_set_name() already does. Use acquire loads in the readers and hold strong references across error reporting, tracing, and eval-frame recording that may execute Python or detach the thread. The __code__, __defaults__, __kwdefaults__ and __closure__ setters still stop the world to clear func_version.

Document synchronization requirements for direct field access and the lifetime of borrowed function attributes.

Benchmark results (release free-threaded build, each thread creates its own function, 5000 iterations, time in seconds):

workload build 1t 2t 4t 8t
set __name__ main 0.002 4.95 4.86 5.99
set __name__ this PR 0.001 0.001 0.001 0.002
set __name__ + __doc__ main 0.004 7.70 10.02 11.47
set __name__ + __doc__ this PR 0.002 0.002 0.001 0.002
functools.wraps main 0.014 18.53 22.58 28.79
functools.wraps this PR 0.010 0.010 0.010 0.014

Note: this PR was created with assistance from LLM agents (Claude Fable and GPT 6.1 Sol).

…ibutes

Setting __name__, __qualname__, __doc__ or __module__ on a function
stopped the world in the free-threaded build since pythongh-154826 and
pythongh-154851, making functools.wraps() orders of magnitude slower with
multiple threads.

Use the per-object critical section and _PyObject_XSetRefDelayed()
instead, as gen_set_name() already does.  Use acquire loads in the
readers and hold strong references across error reporting, tracing, and
eval-frame recording that may execute Python or detach the thread.  The
__code__, __defaults__, __kwdefaults__ and __closure__ setters still
stop the world to clear func_version.

Document synchronization requirements for direct field access and the
lifetime of borrowed function attributes.
@read-the-docs-community

read-the-docs-community Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

@nascheme
nascheme marked this pull request as ready for review October 13, 2026 16:31
Comment thread Include/cpython/funcobject.h
Comment thread Objects/funcobject.c Outdated
@bedevere-app

bedevere-app Bot commented Oct 13, 2026

Copy link
Copy Markdown

When you're done making the requested changes, leave the comment: I have made the requested changes; please review again.

Store func_annotations and func_annotate together before
releasing the old values. Take the function's critical section
in PyFunction_GetAnnotations(). Use an acquire load in
PyFunction_GET_ANNOTATIONS().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants